#include "smoke.h"

void *smoke_thread(void *argv) {
    int32_t i, ret;
    uint8_t ack[SMOKE_ACK_MAX], cmd[9] = {0xff, 0x01, 0x86, 0, 0, 0, 0, 0, 0x79};
    Smoke::SMOKEPARAM *param = (Smoke::SMOKEPARAM *)argv;
    // 循环读取烟雾数据
    while (*param->signal) {
        // 重置数据
        ret = -1;
        memset(ack, 0, sizeof(ack));
        // 烟雾信号
        write(*param->fd, cmd, sizeof(cmd));
        // 等待数据
        sleep(1);
        // 获取数据
        if ((ret = read(*param->fd, ack, sizeof(ack))) != 9) {
            printf("smoke concentration acquisition failed! ret:%d\n", ret);
            continue;
        }
        // 保存数据
        for (i = 0; i < SMOKE_ACK_MAX; i++)
            (*param->ack)[i] = ack[i];
        // 保存浓度
        if (ack[0] == 0xff && ack[1] == 0x86)
            *param->concentration = ack[2] << 8 | ack[3];
    }
    // 退出线程
    pthread_exit(param->tid);
    return NULL;
}

Smoke::Smoke(const string path, const uint32_t baudrate) {
    struct termios termios;
    // 初始化数据
    this->fd = -1, this->tid = -1, this->signal = 0, this->concentration = 0;
    vector< uint8_t >().swap(this->ack);
    memset(&this->param, 0, sizeof(this->param));
    // 打开烟雾传感器
    if ((this->fd = open(path.c_str(), O_RDWR)) == -1)
        throw runtime_error("open '" + path + "' error!\n");
    // 清空数据
    memset(&termios, 0, sizeof(termios));
    // 设置数据
    termios.c_cflag |= (CLOCAL | CREAD); // O_RDWR
    termios.c_cflag &= ~CSIZE;           // 清空数据位
    termios.c_cflag &= ~SMOKE_CRTSCTS;   // 无硬件控制
    termios.c_cflag |= CS8;              // 数据位：8
    termios.c_cflag &= ~CSTOPB;          // 停止位：1
    termios.c_cflag &= ~PARENB;          // 无校验模式
    // 设置波特率
    switch (baudrate) {
    case 9600:
        cfsetospeed(&termios, B9600);
        cfsetispeed(&termios, B9600);
        break;
    case 115200:
        cfsetospeed(&termios, B115200);
        cfsetispeed(&termios, B115200);
        break;
    case 19200:
        cfsetospeed(&termios, B19200);
        cfsetispeed(&termios, B19200);
        break;
    }
    // 刷新输出队列
    tcflush(this->fd, TCIFLUSH);
    // 改变配置
    tcsetattr(this->fd, TCSANOW, &termios);
    // 设置数据最大长度
    this->ack.resize(SMOKE_ACK_MAX);
    //  创建线程
    this->signal = 1;
    this->param.fd = &this->fd;
    this->param.tid = &this->tid;
    this->param.signal = &this->signal;
    this->param.concentration = &this->concentration;
    this->param.ack = &this->ack;
    if (pthread_create(&this->tid, NULL, smoke_thread, &this->param)) {
        close(this->fd);
        throw runtime_error("smoke pthread_create error!\n");
    }
}

Smoke::~Smoke() {
    // 关闭线程
    if (this->signal != 0)
        this->signal = 0;
    // 关闭文件
    if (this->fd != -1)
        close(this->fd);
}

vector< uint8_t > &Smoke::get_ack() {
    return this->ack;
}

uint32_t &Smoke::get_concentration() {
    return this->concentration;
}